/* 
 * Uses custom detection function.  Rule stub just used for autogeneration of base structures.
 *
alert tcp $EXTERNAL_NET any -> $HOME_NET $HTTP_PORTS (msg:"WEB-MISC Apache HTTP server auth_ldap logging function format string vulnerability"; flow:to_server,established; content:"Authorization|3A|"; nocase; pcre:"/^Authorization\x3A\s*Basic[ \t]+/smi";metadata:policy balanced-ips drop, policy security-ips drop, service http; reference:cve,2006-0150; classtype:attempted-user; sid:13308;)
*/
/*
 * This code was automatically generated by the Sourcefire VRT Rules2C web generator
 *
 * We make no claims to the correctness or fitness of the code generated or of modifications
 * to the generated code.
 *
 * Use at your own risk.
 *
 * Please report any problems with this tool to research@sourcefire.com
 */

//#define DEBUG
#ifdef DEBUG
#define DEBUG_SO(code) code
#else
#define DEBUG_SO(code)
#endif


#include "sf_snort_plugin_api.h"
#include "sf_snort_packet.h"
#include "so-util_base64-decode.h"

/* declare detection functions */
int rule13308eval(void *p);

/* declare rule data structures */
/* flow:established, to_server; */
static FlowFlags rule13308flow0 = 
{
    FLOW_ESTABLISHED|FLOW_TO_SERVER
};

static RuleOption rule13308option0 =
{
    OPTION_TYPE_FLOWFLAGS,
    {
        &rule13308flow0
    }
};
// content:"Authorization|3A|", depth 0, nocase, fast_pattern; 
static ContentInfo rule13308content1 = 
{
    (uint8_t *) "Authorization|3A|", /* pattern (now in snort content format) */
    0, /* depth */
    0, /* offset */
    CONTENT_NOCASE|CONTENT_FAST_PATTERN|CONTENT_BUF_NORMALIZED, /* flags */
    NULL, /* holder for boyer/moore PTR */
    NULL, /* more holder info - byteform */
    0, /* byteform length */
    0 /* increment length*/
};

static RuleOption rule13308option1 = 
{
    OPTION_TYPE_CONTENT,
    {
        &rule13308content1
    }
};

// pcre:"^Authorization\x3A\s*Basic[ \t]+", dotall, multiline, nocase;
static PCREInfo rule13308pcre2 =
{
    "^Authorization\\x3A\\s*Basic[ \\t]+", /* pattern */
    NULL,                               /* holder for compiled pattern */
    NULL,                               /* holder for compiled pattern flags */
    PCRE_CASELESS|PCRE_DOTALL|PCRE_MULTILINE,     /* compile flags */
    CONTENT_BUF_NORMALIZED     /* content flags */
};

static RuleOption rule13308option2 =
{
    OPTION_TYPE_PCRE,
    {
        &rule13308pcre2
    }
};

/* references for sid 13308 */
/* reference: cve "2006-0150"; */
static RuleReference rule13308ref1 = 
{
    "cve", /* type */
    "2006-0150" /* value */
};

static RuleReference rule13308ref2 =
{
    "bugtraq", /* type */
    "16177" /* value */
};

static RuleReference *rule13308refs[] =
{
    &rule13308ref1,
    &rule13308ref2,
    NULL
};
/* metadata for sid 13308 */
/* metadata:service http, policy balanced-ips drop, policy security-ips drop; */
static RuleMetaData rule13308service1 = 
{
    "service http"
};
//
//static RuleMetaData rule13308policy1 = 
//{
//    "policy balanced-ips drop"
//};

static RuleMetaData rule13308policy2 = 
{
    "policy security-ips drop"
};

static RuleMetaData rule13308policy3 = 
{
    "policy max-detect-ips drop"
};

static RuleMetaData *rule13308metadata[] =
{
    &rule13308service1,
//    &rule13308policy1,
    &rule13308policy2,
    &rule13308policy3,
    NULL
};

RuleOption *rule13308options[] =
{
    &rule13308option0,
    &rule13308option1,
    &rule13308option2,
    NULL
};

Rule rule13308 = {
   /* rule header, akin to => tcp any any -> any any */
   {
       IPPROTO_TCP, /* proto */
       "$EXTERNAL_NET", /* SRCIP     */
       "any", /* SRCPORT   */
   
       0, /* DIRECTION */
       "$HOME_NET", /* DSTIP     */
   
       "$HTTP_PORTS", /* DSTPORT   */
   },
   /* metadata */
   { 
       3,  /* genid */
       13308, /* sigid */
       12, /* revision */
       "attempted-user", /* classification */
       0,  /* hardcoded priority XXX NOT PROVIDED BY GRAMMAR YET! */
       "SERVER-APACHE Apache HTTP server auth_ldap logging function format string vulnerability",     /* message */
       rule13308refs /* ptr to references */
       ,rule13308metadata
   },
   rule13308options, /* ptr to rule options */
   &rule13308eval, /* replace with NULL to use the built in detection function */
   0 /* am I initialized yet? */
};


/* detection functions */
int rule13308eval(void *p) {
    const uint8_t *cursor_normal = 0;
    const uint8_t *beg_of_buffer, *end_of_buffer;

    SFSnortPacket *sp = (SFSnortPacket *) p;
    
    // Base64 stuff
    uint8_t base64buf[256], decodedbuf[256];
    uint32_t inputchars, base64bytes, decodedbytes;

    int i;

    if(sp == NULL)
        return RULE_NOMATCH;

    // flow:established, to_server;
    if (checkFlow(p, rule13308options[0]->option_u.flowFlags) <= 0)
        return RULE_NOMATCH;

    // Doing this content match is pretty useless because it's duplicated in our PCRE.
    // But we want to keep the structure for the pattern matcher.
//    // content:"Authorization|3A|", depth 0, nocase, fast_pattern;
//    if (contentMatch(p, rule13308options[1]->option_u.content, &cursor_normal) <= 0)
//        return RULE_NOMATCH;

    // pcre:"^Authorization\x3A\s*Basic[ \t]+", dotall, multiline, nocase;
    if (pcreMatch(p, rule13308options[2]->option_u.pcre, &cursor_normal) <= 0)
        return RULE_NOMATCH;

    if(getBuffer(sp, CONTENT_BUF_NORMALIZED, &beg_of_buffer, &end_of_buffer) != CURSOR_IN_BOUNDS)
        return RULE_NOMATCH;

    // At this point, cursor should point to the start of the auth data
    inputchars = (end_of_buffer > cursor_normal + sizeof(base64buf)) ? sizeof(base64buf) : end_of_buffer - cursor_normal;

    DEBUG_SO(printf("%d input chars: %*s\n", inputchars, inputchars, cursor_normal));

    if(unfold_header(cursor_normal, inputchars, base64buf, sizeof(base64buf), &base64bytes) != 0)
        return RULE_NOMATCH;

    DEBUG_SO(printf("Successfully unfolded header (%s)(%d)\n", base64buf, base64bytes));

    if(base64decode(base64buf, base64bytes, decodedbuf, sizeof(decodedbuf), &decodedbytes) < 0)
        return RULE_NOMATCH;

    DEBUG_SO(printf("Successfully base64 decoded (%s)(%d)\n", decodedbuf, decodedbytes));
  
    for(i=0; i<decodedbytes; i++) {
        DEBUG_SO(printf("checking byte: %c\n", decodedbuf[i]));
        if(decodedbuf[i] == '%') {
            return RULE_MATCH;
        } else if(decodedbuf[i] == ':') {
            // Separator between username:password
            return RULE_NOMATCH;
        }
    }        
        
    return RULE_NOMATCH;
}

/*
Rule *rules[] = {
    &rule13308,
    NULL
};
*/
